﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using HtmlAgilityPack;
using Travan.ServerServices.CustomObjects;
using Travan.ServerServices.Interfaces;
using TravianAutoQueue.DomainModel;
using TravianAutoQueue.DomainModel.Enums;

namespace Travan.ServerServices
{
    public class VillageService : IVillageService
    {

        #region IVillageService Members

        
        public IHttpHelpers Httphelper { get; set; }
        public ITravianHelpers TravianHelper { get; set; }

        public Cost GetVillageResource(int villageid, TravianSession session)
        {
            if (TravianHelper.CheckIfLoginPage(session))
                TravianHelper.Login(session);

            Httphelper.Get(string.Format("http://{0}/dorf1.php?newdid={1}", session.Server, villageid), session);

            var resobar = session.CurrentDocument.GetElementbyId("resWrap").SelectSingleNode("./table/tr[1]");

            var woodcount = Convert.ToInt32( Regex.Match(resobar.SelectSingleNode("./td[2]").InnerText, @"(\d+)\/(\d+)").Groups[1].Value);
            var claycount = Convert.ToInt32(Regex.Match(resobar.SelectSingleNode("./td[4]").InnerText, @"(\d+)\/(\d+)").Groups[1].Value);
            var ironcount = Convert.ToInt32(Regex.Match(resobar.SelectSingleNode("./td[6]").InnerText, @"(\d+)\/(\d+)").Groups[1].Value);
            var cropcount = Convert.ToInt32(Regex.Match(resobar.SelectSingleNode("./td[8]").InnerText, @"(\d+)\/(\d+)").Groups[1].Value);

            return new Cost() {Clay = claycount, Crop = cropcount, Wood = woodcount, Iron = ironcount};
            
        }

        public List<Village> GetVillages(TravianSession session)
        {
            if (TravianHelper.CheckIfLoginPage(session))
                TravianHelper.Login(session);
            
            Httphelper.Get(string.Format("http://{0}/dorf1.php", session.Server), session);

            var villagetable = session.CurrentDocument.GetElementbyId("vlist").SelectNodes("./tbody/tr");

            var results = new List<Village>();

            foreach (HtmlNode node in villagetable)
            {
                var village = new Village();
                var anchortag = node.Descendants("a").Single();
                village.X=Convert.ToInt32( Regex.Match(node.SelectSingleNode("td[@class='aligned_coords']/div[@class='cox']").InnerText, @"\((-?\d+)").Groups[1].Value);
                village.Y = Convert.ToInt32(Regex.Match(node.SelectSingleNode("td[@class='aligned_coords']/div[@class='coy']").InnerText, @"(-?\d+).*").Groups[1].Value);
                village.Name = anchortag.InnerText;
                village.TravianId =
                    Convert.ToInt32(Regex.Match(anchortag.GetAttributeValue("href",""), @".*newdid\=(\d*).*").Groups[1].Value );
                

                results.Add(village );
            }

            return results;
        }

        public TimeSpan GetCurrentQueueEnd(TravianSession session, int villageid)
        {
            if (TravianHelper.CheckIfLoginPage(session))
                TravianHelper.Login(session);

            session=Httphelper.Get(string.Format("http://{0}/dorf1.php?newdid={1}", session.Server, villageid), session);

            return GetCurrentQueueEnd(session.CurrentDocument);
        }

        
        public TimeSpan UpgradeBuilding(int slotnumber, int villageid, TravianSession session)
        {
            if (TravianHelper.CheckIfLoginPage(session))
                TravianHelper.Login(session);

            session = Httphelper.Get(string.Format("http://{0}/build.php?newdid={1}&id={2}", session.Server, villageid,slotnumber), session);

            var upgradelink = session.CurrentDocument.GetElementbyId("contract").SelectSingleNode("./a[@class='build']");

            if (upgradelink == null)
            {
                throw new Exception("The building cannot be created yet");
            }

            session = Httphelper.Get(string.Format("http://{0}/{1}", session.Server, upgradelink.GetAttributeValue("href","")), session);

            return GetCurrentQueueEnd(session.CurrentDocument);
        }

        public List<VillageBuilding> GetResourcePlateLevels(int villageid, TravianSession session)
        {
            if (TravianHelper.CheckIfLoginPage(session))
                TravianHelper.Login(session);
            var results = new List <VillageBuilding>();
            session = Httphelper.Get(string.Format("http://{0}/dorf1.php?newdid={1}", session.Server, villageid), session);

            //Get Template
            var resourcetemplate = this.GetResourceTemplate(session.CurrentDocument.GetElementbyId("village_map").GetAttributeValue("class",""));


            var resources = session.CurrentDocument.GetElementbyId("village_map").SelectNodes("img[@class]");

            foreach (HtmlNode reso in resources)
            {
                var match = Regex.Match(reso.GetAttributeValue("class", ""), @"reslevel rf(\d*) level(\d*)");
                var fieldid = Convert.ToInt32(match.Groups[1].Value);
                var level = Convert.ToInt32(match.Groups[2].Value);
                results.Add( new VillageBuilding() {BuildingType = resourcetemplate[fieldid], Level=level, SlotNumber= fieldid});
                
            }

            return results;
        }
        #endregion


        #region "Private Helpers"

        private TimeSpan GetCurrentQueueEnd(HtmlDocument document)
        {
            var queue = document.GetElementbyId("building_contract");
            if (queue == null)
            {
                return new TimeSpan(0);
            }

            var timespan = queue.SelectSingleNode("./tbody/tr[1]/td/span[@id]").InnerText;

            var endtime = TimeSpan.Parse(timespan);

            return endtime;
        }

        private Dictionary<int, BuildingType> GetResourceTemplate(string templatename)
        {
            var returnvalue = new Dictionary<int, BuildingType>();
            switch(templatename)
            {
                case "f1":
                    returnvalue.Add(1,BuildingType.Cropland);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.Cropland);
                    returnvalue.Add(5, BuildingType.Cropland);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland );
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f2":
                    returnvalue.Add(1, BuildingType.IronMine);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.IronMine);
                    returnvalue.Add(5, BuildingType.ClayPit );
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland  );
                    returnvalue.Add(9, BuildingType.Cropland  );
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f3":
                    returnvalue.Add(1, BuildingType.Woodcutter );
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.IronMine);
                    returnvalue.Add(5, BuildingType.ClayPit);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f4":
                    returnvalue.Add(1, BuildingType.Woodcutter);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.ClayPit );
                    returnvalue.Add(5, BuildingType.ClayPit);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f5":
                    returnvalue.Add(1, BuildingType.Woodcutter);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.IronMine );
                    returnvalue.Add(5, BuildingType.Woodcutter );
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f6":
                    returnvalue.Add(1, BuildingType.Cropland );
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.IronMine);
                    returnvalue.Add(5, BuildingType.Cropland);
                    returnvalue.Add(6, BuildingType.Cropland );
                    returnvalue.Add(7, BuildingType.Cropland );
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.Cropland);
                    returnvalue.Add(11, BuildingType.Cropland);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Cropland);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Cropland);
                    returnvalue.Add(18, BuildingType.Cropland);
                    break;
                case "f7":
                    returnvalue.Add(1, BuildingType.Woodcutter);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Cropland);
                    returnvalue.Add(4, BuildingType.Woodcutter);
                    returnvalue.Add(5, BuildingType.ClayPit );
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit );
                    returnvalue.Add(17, BuildingType.Woodcutter );
                    returnvalue.Add(18, BuildingType.ClayPit );
                    break;
                case "f8":
                    returnvalue.Add(1, BuildingType.IronMine);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Cropland);
                    returnvalue.Add(4, BuildingType.Woodcutter);
                    returnvalue.Add(5, BuildingType.ClayPit);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f9":
                    returnvalue.Add(1, BuildingType.IronMine);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Cropland);
                    returnvalue.Add(4, BuildingType.Woodcutter);
                    returnvalue.Add(5, BuildingType.Woodcutter);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f10":
                    returnvalue.Add(1, BuildingType.IronMine);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.ClayPit );
                    returnvalue.Add(5, BuildingType.ClayPit);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f11":
                    returnvalue.Add(1, BuildingType.IronMine);
                    returnvalue.Add(2, BuildingType.Woodcutter );
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.IronMine );
                    returnvalue.Add(5, BuildingType.Woodcutter );
                    returnvalue.Add(6, BuildingType.Cropland);
                    returnvalue.Add(7, BuildingType.Cropland);
                    returnvalue.Add(8, BuildingType.IronMine );
                    returnvalue.Add(9, BuildingType.IronMine );
                    returnvalue.Add(10, BuildingType.ClayPit);
                    returnvalue.Add(11, BuildingType.ClayPit);
                    returnvalue.Add(12, BuildingType.IronMine );
                    returnvalue.Add(13, BuildingType.Woodcutter );
                    returnvalue.Add(14, BuildingType.Cropland );
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Cropland );
                    returnvalue.Add(18, BuildingType.Cropland);
                    break;
                case "f12":
                    returnvalue.Add(1, BuildingType.Woodcutter);
                    returnvalue.Add(2, BuildingType.Cropland );
                    returnvalue.Add(3, BuildingType.Woodcutter );
                    returnvalue.Add(4, BuildingType.Woodcutter );
                    returnvalue.Add(5, BuildingType.ClayPit);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine );
                    returnvalue.Add(8, BuildingType.Cropland );
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine );
                    returnvalue.Add(11, BuildingType.IronMine );
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland );
                    returnvalue.Add(16, BuildingType.ClayPit );
                    returnvalue.Add(17, BuildingType.Woodcutter );
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                case "f13":
                    returnvalue.Add(1, BuildingType.Woodcutter);
                    returnvalue.Add(2, BuildingType.Cropland);
                    returnvalue.Add(3, BuildingType.Woodcutter);
                    returnvalue.Add(4, BuildingType.Woodcutter);
                    returnvalue.Add(5, BuildingType.ClayPit);
                    returnvalue.Add(6, BuildingType.ClayPit);
                    returnvalue.Add(7, BuildingType.IronMine);
                    returnvalue.Add(8, BuildingType.Cropland);
                    returnvalue.Add(9, BuildingType.Cropland);
                    returnvalue.Add(10, BuildingType.IronMine);
                    returnvalue.Add(11, BuildingType.IronMine);
                    returnvalue.Add(12, BuildingType.Cropland);
                    returnvalue.Add(13, BuildingType.Cropland);
                    returnvalue.Add(14, BuildingType.Woodcutter);
                    returnvalue.Add(15, BuildingType.Cropland);
                    returnvalue.Add(16, BuildingType.ClayPit);
                    returnvalue.Add(17, BuildingType.Woodcutter);
                    returnvalue.Add(18, BuildingType.ClayPit);
                    break;
                    default:
                    throw new Exception("The field template could not be located");
            }
            return returnvalue;
        }


        #endregion
    }
}
